﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using BAC.Excel.Engine;
using BAC.Operations.Engine;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Metadata;
using System.Windows.Media;
using McTools.Xrm.Connection;
using BAC.CRMService.UI.Engine;
using Microsoft.Crm.Sdk.Messages;


namespace BAC.UI.Engine
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class BACWindow : Window
    {
        //private OrganizationServiceProxy _serviceProxy;
        Dictionary<string, string> targetEntityNameResolver = new Dictionary<string, string>();
        Dictionary<string, string> publisherPrefixResolver = new Dictionary<string, string>();
        DataTable gridDataSourceTable = new DataTable();
        List<string> lookupEntityDisplayNames = new List<string>();
        List<string> targetEntityDisplayNames = new List<string>();
        Dictionary<string, string> lookupEntityNameResolver = new Dictionary<string, string>();
        DataTable gridDataTable = new DataTable();
        string currentLookupTarget = string.Empty;
        string selectedEntityName = string.Empty;
        string prefix = string.Empty;
        string previousPrefix = string.Empty;
        public static Dictionary<int, string> operationErrorRowList = new Dictionary<int, string>();
        public static List<string> operationErrorList = new List<string>();
        List<string> defaultLookupEntityList = new List<string> {"account","activitypointer","appointment","businessunit","campaign","campaignactivity","campaignresponse","competitor",
        "constraintbasedgroup","contact","contract","contractdetail","contracttemplate","customeraddress","discounttype","email","emailserverprofile","equipment","fax","goal","goalrollupquery","importmap",
        "incident","invoice","kbarticle","kbarticletemplate","lead","letter","list","mailbox","mailmergetemplate","mbs_pluginprofile","metric","msdyn_postalbum","msdyn_postconfig","msdyn_postruleconfig","msdyn_wallsavedquery",
        "msdyn_wallsavedqueryusersettings","opportunity","partnerapplication","phonecall","pricelevel","product","queue","quote","recurringappointmentmaster","relationshiprole","resourcespec","role",
        "salesliterature","salesorder","service","serviceappointment","sharepointdocumentlocation","sharepointsite","site","subject","systemuser","task","team","territory","transactioncurrency","uom","uomschedule","workflow"
        };
        #region Variables

        /// <summary>
        /// Dynamics CRM 2011 organization service
        /// </summary>
        IOrganizationService service;

        /// <summary>
        /// Connection control
        /// </summary>
        //CrmConnectionStatusBar ccsb;

        /// <summary>
        /// Connection manager
        /// </summary>
        ConnectionManager cManager;

        private WindowHelper formHelper;

        #endregion Variables
        public BACWindow()
        {
            //CRMServiceInitiater objCRMServiceInitiater = new CRMServiceInitiater();
            //_serviceProxy = objCRMServiceInitiater.CrmOrgServiceProxy;

            ExcelConstants ex = new ExcelConstants();
            InitializeComponent();
            // Create the connection manager with its events
            this.cManager = new ConnectionManager();
            this.cManager.ConnectionSucceed += new ConnectionManager.ConnectionSucceedEventHandler(cManager_ConnectionSucceed);
            this.cManager.ConnectionFailed += new ConnectionManager.ConnectionFailedEventHandler(cManager_ConnectionFailed);
            this.cManager.StepChanged += new ConnectionManager.StepChangedEventHandler(cManager_StepChanged);
            this.cManager.RequestPassword += new ConnectionManager.RequestPasswordEventHandler(cManager_RequestPassword);
            //this.cManager.UseProxy += new ConnectionManager.UseProxyEventHandler(cManager_UseProxy);
            formHelper = new WindowHelper(this, cManager);

        }

        /// <summary>
        /// Submit Button OnClick Handler
        /// </summary>
        private void btnSubmit_Click(object sender, RoutedEventArgs e)
        {
            operationErrorList = new List<string>();
            operationErrorRowList = new Dictionary<int, string>();
            CrmOperationsHelper.ProcessAttributes(gridDataTable, service, selectedEntityName, lookupEntityNameResolver, out operationErrorList);

            string strError = string.Empty;
            if (operationErrorList.Count > 0)
            {
                int count = 1;
                foreach (string error in operationErrorList)
                {
                    string[] errorArray = error.Split(new Char[] { ';' });
                    if (errorArray.Length > 0)
                    {
                        int startingIndex = errorArray[0].IndexOf("{");
                        int endIndex = errorArray[0].IndexOf("}");
                        if (startingIndex != -1 && endIndex != -1)
                        {
                            string strRowNumber = errorArray[0].Substring(startingIndex + 1, (endIndex - 1) - startingIndex);
                            int rowNumber = -1;
                            if (int.TryParse(strRowNumber, out rowNumber))
                            {
                                operationErrorRowList.Add(rowNumber, errorArray[1]);
                            }
                        }
                    }
                    if (string.IsNullOrEmpty(strError))
                    {
                        strError = count.ToString() + ">" + error;
                    }
                    else
                    {
                        strError = strError + System.Environment.NewLine + count.ToString() + ">" + error;
                    }
                    count++;
                }

                operationErrorRowList.OrderBy(i => i.Key);
                Dictionary<int, string> tempDict = new Dictionary<int, string>();
                foreach (var item in operationErrorRowList.OrderBy(i => i.Key))
                {
                    tempDict.Add(item.Key, item.Value);
                }
                operationErrorRowList = tempDict;
                for (int index = 0; index < (dataGrid1.Items.Count); index++)
                {
                    if (operationErrorRowList.ContainsKey(index + 1))
                    {
                        gridDataTable.Rows[index][ExcelConstants.StatusHeader] = operationErrorRowList[index + 1];
                    }

                    else
                    {
                        gridDataTable.Rows[index][ExcelConstants.StatusHeader] = "Success";

                    }

                }
                dataGrid1.ItemsSource = gridDataTable.AsDataView();
                if (!string.IsNullOrEmpty(strError))
                {
                    //MessageBox.Show(strError, "Error List");
                    MessageBox.Show("Attribute creation failed for some attributes.Check the inline status", "Status");
                }
                else
                {
                    MessageBox.Show("All Attributes Created Successfully", "Status");
                }
                for (int index = 0; index < (dataGrid1.Items.Count); index++)
                {

                    var row = dataGrid1.ItemContainerGenerator.ContainerFromIndex(index) as DataGridRow;
                    //int rowIndex = row.GetIndex() + 1;
                    if (operationErrorRowList.ContainsKey(index + 1))
                    {
                        row.Background = Brushes.LightPink;
                    }

                    else
                    {
                        row.Background = Brushes.LightGreen;

                    }

                }


            }

        }

        /// <summary>
        /// Browse Button OnClick Handler
        /// </summary>
        private void btnBrowse_Click(object sender, RoutedEventArgs e)
        {
            Microsoft.Win32.OpenFileDialog fileDlg = new Microsoft.Win32.OpenFileDialog();
            fileDlg.DefaultExt = ".xlsm";
            fileDlg.Filter = "Excel macros(*.xlsm)|*.xlsm";
            if (!string.IsNullOrEmpty(tbFilenName.Text))
            {
                fileDlg.FileName = tbFilenName.Text;
            }

            // Display OpenFileDialog by calling ShowDialog method 
            Nullable<bool> result = fileDlg.ShowDialog();
            if (result == true)
            {
                tbFilenName.Text = fileDlg.FileName;
                //DataView dv = ExcelHelper.GetDataFromExcel(tbFilenName.Text).AsDataView();
                gridDataSourceTable = ExcelHelper.GetDataFromExcel(tbFilenName.Text);
                //prefix = SetPrefixFromPublisher();
                gridDataTable = ExcelHelper.SetAttributeNamePrefix(gridDataSourceTable, prefix, previousPrefix);
                dataGrid1.ItemsSource = gridDataTable.AsDataView();
                //TargetRecordType.ItemsSource = lookupEntityNameResolver;

                dataGrid1.IsReadOnly = false;
                Resources["lookupEntityNameResolver"] = lookupEntityNameResolver;

            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MyWindow_Loaded(object sender, RoutedEventArgs e)
        {
            SetControlsEnabledState(false);
            LoadPreData();

        }

        private void LoadPreData()
        {
            if (service != null)
            {
                SetControlsEnabledState(true);
                EntityMetadataCollection entityMetadataCollection = CrmOperationsHelper.GetAllValidEntityCollection(service);
                EntityCollection publisherList = CrmOperationsHelper.GetPublishersList(service);
                foreach (var publisher in publisherList.Entities)
                {
                    string FriendlyName = publisher["friendlyname"].ToString();
                    Guid PublisherId = (Guid)publisher["publisherid"];
                    string UniqueName = publisher["uniquename"].ToString();
                    string CustomizationPrefix = publisher["customizationprefix"].ToString();
                    cbPublisher.Items.Add(FriendlyName);
                    publisherPrefixResolver.Add(FriendlyName, CustomizationPrefix);
                    cbPublisher.SelectedIndex = 0;
                }

                foreach (EntityMetadata entityMetadata in entityMetadataCollection)
                {
                    if (entityMetadata.DisplayName.LocalizedLabels.Count > 0)
                    {
                        string displayName = entityMetadata.DisplayName.LocalizedLabels[0].Label;
                        string logicalName = entityMetadata.LogicalName.ToString();


                        if (defaultLookupEntityList.Contains(logicalName) || entityMetadata.IsCustomEntity.Value)
                        {
                            string entityDisplayName = entityMetadata.DisplayName.LocalizedLabels[0].Label;
                            string entityName = entityMetadata.LogicalName;
                            lookupEntityDisplayNames.Add(entityDisplayName);
                            lookupEntityNameResolver.Add(entityDisplayName, entityName);
                        }


                        if (entityMetadata.CanCreateAttributes.Value)
                        {
                            string entityDisplayName = entityMetadata.DisplayName.LocalizedLabels[0].Label;
                            string entityName = entityMetadata.LogicalName;
                            targetEntityDisplayNames.Add(entityDisplayName);
                            targetEntityNameResolver.Add(entityDisplayName, entityName);
                        }

                    }

                }
                lookupEntityDisplayNames.Sort();
                targetEntityDisplayNames.Sort();
                Dictionary<string, string> tempDict = new Dictionary<string, string>();
                foreach (var item in lookupEntityNameResolver.OrderBy(i => i.Key))
                {
                    tempDict.Add(item.Key, item.Value);
                }
                lookupEntityNameResolver = tempDict;
                cbEntity.ItemsSource = targetEntityDisplayNames;
                cbEntity.SelectedIndex = 0;
                SetPrefixFromPublisher();
            }
        }
        private void UnloadPreData()
        {

            SetControlsEnabledState(false);

            cbPublisher.Items.Clear();
            lookupEntityDisplayNames.Clear();
            lookupEntityNameResolver.Clear();
            targetEntityDisplayNames.Clear();
            targetEntityNameResolver.Clear();

            cbEntity.ItemsSource = targetEntityDisplayNames;
            cbEntity.SelectedItem = null;

            publisherPrefixResolver.Clear();
            tbFilenName.Text = string.Empty;
            gridDataSourceTable.Clear();
            gridDataTable.Clear();
            dataGrid1.ColumnWidth = DataGridLength.Auto;
            currentLookupTarget = string.Empty;
            selectedEntityName = string.Empty;
            prefix = string.Empty;
            previousPrefix = string.Empty;
            operationErrorRowList.Clear();
            operationErrorList.Clear();
            btnConnect.IsEnabled = true;
            lblConnectionStatus.Content = "Not Connected";
            this.service = null;
            lblConnectionStatus.Foreground = System.Windows.Media.Brushes.Red;

        }

        private void SetControlsEnabledState(bool isEnabled)
        {
            tbFilenName.IsEnabled = isEnabled;
            btnBrowse.IsEnabled = isEnabled;
            btnSubmit.IsEnabled = isEnabled;
            cbEntity.IsEnabled = isEnabled;
            cbPublisher.IsEnabled = isEnabled;
        }
        private void cbEntity_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            int selectedIndex = cbEntity.SelectedIndex;
            if (selectedIndex >= 0)
            {
                string selectedText = cbEntity.Items[selectedIndex].ToString();
                if (!string.IsNullOrEmpty(selectedText) && targetEntityNameResolver.ContainsKey(selectedText))
                {
                    selectedEntityName = targetEntityNameResolver[selectedText].ToString();
                }
            }
            else
            {
                selectedEntityName = string.Empty;
            }
        }

        private void cbPublisher_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            SetPrefixFromPublisher();
            if (!string.IsNullOrEmpty(prefix))
            {
                if (gridDataSourceTable.Rows.Count > 0)
                {
                    DataTable dt = ExcelHelper.SetAttributeNamePrefix(gridDataSourceTable, prefix, previousPrefix);
                    dataGrid1.ItemsSource = dt.AsDataView();
                }
            }
        }

        private void dataGrid1_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
        {
            int index = e.Row.GetIndex();
            if (gridDataTable.Rows[index][ExcelConstants.AttributeTypeHeader].ToString() == "Lookup")
            {
                if (!string.IsNullOrEmpty(currentLookupTarget) && lookupEntityNameResolver.ContainsKey(currentLookupTarget))
                {
                    gridDataTable.Rows[index][15] = currentLookupTarget;
                    string attributeName = gridDataTable.Rows[index][ExcelConstants.NameHeader].ToString();
                    string referencedEntity = lookupEntityNameResolver[currentLookupTarget].ToString();
                    string currentDefaultRelationshipName = GetDefaultRelationshipName(referencedEntity, selectedEntityName, attributeName);
                    gridDataTable.Rows[index][16] = currentDefaultRelationshipName;
                }
                currentLookupTarget = string.Empty;
                dataGrid1.ItemsSource = gridDataTable.AsDataView();
            }
        }

        private void dataGrid1_CurrentCellChanged(object sender, EventArgs e)
        {
        }

        private void cbLookupType_DropDownClosed(object sender, EventArgs e)
        {
            ComboBox cb = (ComboBox)sender;
            currentLookupTarget = cb.Text;
        }

        private void SetPrefixFromPublisher()
        {
            var strSelectedValue = cbPublisher.SelectedValue;
            string selectedText = string.Empty;
            if (strSelectedValue != null)
            {
                selectedText = cbPublisher.SelectedValue.ToString();
            }

            previousPrefix = prefix;
            if (!string.IsNullOrEmpty(selectedText))
            {
                prefix = publisherPrefixResolver[selectedText].ToString();
            }
            else
            {
                prefix = string.Empty;
            }
            //return prefix;
        }

        private string GetDefaultRelationshipName(string referencedEntity, string referencingEntity, string attributeName)
        {
            string strRelationshipSchemaName = string.Empty;
            string relationShipPrefix = string.Empty;
            if (string.IsNullOrEmpty(prefix))
            {
                relationShipPrefix = "new";

            }
            else
            {
                relationShipPrefix = prefix;
            }
            strRelationshipSchemaName = relationShipPrefix + "_" + referencingEntity + "_" + referencedEntity + "_" + attributeName;
            return strRelationshipSchemaName;
        }
        #region Connection MEthods
        private void btnConnect_Click(object sender, RoutedEventArgs e)
        {
            btnConnect.IsEnabled = false;
            if (this.service == null)
            {
                formHelper.AskForConnection("WhoAmI");
            }
            else
            {
                WhoAmI();
            }
            btnConnect.IsEnabled = true;
        }
        bool cManager_RequestPassword(object sender, RequestPasswordEventArgs e)
        {
            return formHelper.RequestPassword(e.ConnectionDetail);
        }
        #endregion
        #region Connection event handlers

        /// <summary>
        /// Occurs when the connection manager sends a step change
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void cManager_StepChanged(object sender, StepChangedEventArgs e)
        {
            //this.ccsb.SetMessage(e.CurrentStep);
        }

        /// <summary>
        /// Occurs when the connection to a server failed
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void cManager_ConnectionFailed(object sender, ConnectionFailedEventArgs e)
        {
            // Set error message
            //this.ccsb.SetMessage("Error: " + e.FailureReason);

            // Clear the current organization service
            this.service = null;
            lblConnectionStatus.Content = "Not Connected";
            lblConnectionStatus.Foreground = System.Windows.Media.Brushes.Red;
            btnConnect.IsEnabled = true;
        }

        /// <summary>
        /// Occurs when the connection to a server succeed
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void cManager_ConnectionSucceed(object sender, ConnectionSucceedEventArgs e)
        {
            // Store connection Organization Service
            this.service = e.OrganizationService;
            lblConnectionStatus.Content = "Connected";
            lblConnectionStatus.Foreground = System.Windows.Media.Brushes.Green;

            // Do action if needed
            //if (e.Parameter != null)
            //{
            //    if (e.Parameter.ToString() == "WhoAmI")
            //    {
            //        WhoAmI();
            //    }
            //}

            LoadPreData();
            btnConnect.IsEnabled = true;
        }

        #endregion Connection event handlers

        #region WhoAmI Sample methods

        private void WhoAmI()
        {
            WhoAmIRequest request = new WhoAmIRequest();
            WhoAmIResponse response = (WhoAmIResponse)this.service.Execute(request);

            MessageBox.Show(this, "Your ID is: " + response.UserId.ToString("B"));
        }

        #endregion WhoAmI Sample methods

        private void btnReset_Click(object sender, RoutedEventArgs e)
        {
            UnloadPreData();
        }

        private void btnDownload_Click(object sender, RoutedEventArgs e)
        {
            //System.Windows.Form.FolderBrowserDialog used because of no Folder Browser support in WPF
            //TODO: Find some alternative to this approach
            var dialog = new System.Windows.Forms.FolderBrowserDialog();
            System.Windows.Forms.DialogResult result = dialog.ShowDialog();
            if (result == System.Windows.Forms.DialogResult.OK)
            {
                ExcelHelper.SaveAsXltm(dialog.SelectedPath.ToString());
            }

        }
    }
}
